"""
交易模块，负责股票买卖
"""
import pandas as pd
import numpy as np
import log
import stock

stock_data = stock.stock_data


class Trade(object):

    def __init__(self, money):
        # 初始手中现金
        self.money = money
        # 可支配现金,初始等于手中所有现金
        self.free_money = self.money
        # 持仓股票，设计成一个dataframe，每变动一次就填入数据，原始持仓为空
        row_hold = pd.DataFrame(data=0.00,
                                index=stock.stock_list,
                                columns=["持仓数量", "成本价", "现价（收盘价）",
                                         "今日收益", "累计收益", "买入日期"])
        # 持仓
        self.hold = row_hold

    # 买入操作
    def buy(self, stock, amount, day):
        """
        :param stock: 买入的股票实例（策略来判断）
        :param amount: 买入数量(手，1手为100股）（是数量，不是金额）（策略来判断）（amount_list)
        :param day: 买入日期（策略来判断）(trade_list)
        :return:
        """
        # 单价
        buy_price = self.trade_price(stock, day)

        if np.isnan(buy_price):
            print("因一些原因，本只股票今日无法交易！")

        else:
            # 订单预期总价（未包含交易费用）
            trade_amount = buy_price * amount * 100
            fee = self.fee(trade_amount, 0)

            if self.free_money >= trade_amount + fee:

                self.free_money = self.free_money - trade_amount - fee
                # 加权平均成本价
                buy_cost = (((self.hold.loc[stock.code, "持仓数量"] * 100) * (self.hold.loc[stock.code, "成本价"]))
                            + trade_amount + fee) / (amount * 100 + 100 * self.hold.loc[stock.code, "持仓数量"])
                # 剩余数量
                left_num = amount + self.hold.loc[stock.code, "持仓数量"]
                # 更新持仓信息
                self.hold.loc[stock.code, :] = [left_num, buy_cost, stock.get_close(day), None, None, day]
                # 写入日志
                log.write_log("买入股票[{0}]成功，买入{1}手，现持有{3}手，剩余资金{2}元。\n"
                              .format(stock.code, amount, self.free_money, left_num))
                print("[%s]买入成功，买入%d手" % (stock.code, amount))
            else:
                print("[%s]买入失败,余额不足！" % stock.code)

    # 卖出操作
    def sell(self, stock, amount, day):
        """
        :param share: 卖出股票
        :param amount: 卖出数量
        :param day: 卖出日期
        :return:
        """
        sell_price = self.trade_price(stock, day)
        if np.isnan(sell_price):

            print("因一些原因，本只股票今日无法交易！")

        else:
            trade_amount = sell_price * amount * 100
            fee = self.fee(trade_amount, 1)

            if self.hold.loc[stock.code, "持仓数量"] >= amount:

                self.free_money = self.free_money + trade_amount - fee

                left_num = self.hold.loc[stock.code, "持仓数量"] - amount
                if left_num > 0:
                    cost_now = (((self.hold.loc[stock.code, "持仓数量"] * 100) * (self.hold.loc[stock.code, "成本价"]))
                                - trade_amount + fee) / (left_num * 100)
                    self.hold.loc[stock.code, "持仓数量": "累计收益"] = [left_num, cost_now, stock.get_close(day), None, None]
                else:
                    self.hold.loc[stock.code, :] = [left_num, 0.00, stock.get_close(day), None, None, None]
                log.write_log("卖出股票[{0}]成功，卖出{1}手，现持有{3}手，剩余资金{2}元。\n"
                              .format(stock.code, amount, self.free_money, left_num))
                print("[%s]卖出成功！卖出%d手" % (stock.code, amount))
            else:
                print("[%s]卖出失败，持仓数量不足！" % stock.code)

    # 更新 获取  某一日的持仓情况（收盘后）
    def get_hold(self, date):
        """
        :param date: 获取的日期
        :return: 返回一个持仓信息，要完全的
        """
        for item in self.hold.index:
            if self.hold.loc[item, "持仓数量"] > 0:
                self.hold.loc[item, "现价（收盘价）": "累计收益"] = [stock.Stock(item).get_close(date),
                                                          stock.Stock(item).cal_today_return(date),
                                                          stock.Stock(item).cal_total_return(
                                                              self.hold.loc[item, "买入日期"], date)]
        return self.hold

    # 计算交易手续费
    @staticmethod
    def fee(amount, trade_type=0):
        """
        :param self:
        :param amount: 交易总金额
        :param trade_type: 交易类型
        :return:
        """
        # rate_1 = 0  # 券商佣金（买卖都收）
        # rate_2 = 0  # 过户费（买卖都收）
        # rate_3 = 0  # 印花税（卖的时候收）
        rate_1 = 0.00025  # 券商佣金（买卖都收）
        rate_2 = 0.0002  # 过户费（买卖都收）
        rate_3 = 0.001  # 印花税（卖的时候收）
        # 0 代表买
        if trade_type == 0:
            total_fee = amount * (rate_1 + rate_2)
        # 1 代表卖
        else:
            total_fee = amount * (rate_1 + rate_2 + rate_3)
        return total_fee

    # 获取交易价格（开盘价）
    @staticmethod
    def trade_price(stock, day):
        """
        :param stock: 股票
        :param day: 日期
        :return: 返回交易的价格
        """
        # 买入价格，开盘价买入
        price = stock.get_open(day)
        return price
